package com.lishang.location.helper.ui

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.location.Location
import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.paging.*
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import com.lishang.location.helper.R
import com.lishang.location.helper.databinding.ActivityMapBinding
import com.lishang.location.helper.databinding.ItemPoiLayoutBinding
import com.lishang.location.helper.manager.SpManager
import com.lishang.location.helper.receiver.MainReceiver
import com.tencent.lbssearch.TencentSearch
import com.tencent.lbssearch.`object`.param.Geo2AddressParam
import com.tencent.lbssearch.`object`.result.Address2GeoResultObject
import com.tencent.lbssearch.`object`.result.Geo2AddressResultObject
import com.tencent.lbssearch.httpresponse.BaseObject
import com.tencent.lbssearch.httpresponse.Poi
import com.tencent.map.geolocation.TencentLocation
import com.tencent.map.geolocation.TencentLocationListener
import com.tencent.map.geolocation.TencentLocationManager
import com.tencent.map.tools.net.http.HttpResponseListener
import com.tencent.tencentmap.mapsdk.maps.LocationSource
import com.tencent.tencentmap.mapsdk.maps.SupportMapFragment
import com.tencent.tencentmap.mapsdk.maps.TencentMap
import com.tencent.tencentmap.mapsdk.maps.model.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine


class MapActivity : AppCompatActivity(), LocationSource, TencentLocationListener {
    companion object {
        const val TAG = "MapActivity"
    }

    private val binding by lazy {
        ActivityMapBinding.inflate(layoutInflater)
    }
    private lateinit var mTencentMap: TencentMap
    private var isLocationOk = false
    private val centerPositionDrawable by lazy {
        BitmapDescriptorFactory.fromResource(R.drawable.b4q)
    }
    private val mLocationManager by lazy {
        TencentLocationManager.getInstance(applicationContext)
    }

    private val mSearchPoi by lazy {
        PoiSearch(this)
    }

    private val mPoiAdapter by lazy { PoiAdapter() }

    private var mLocationChangedListener: LocationSource.OnLocationChangedListener? = null
    private var mClickMarker: Marker? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        initView()
        initMap()


    }

    private fun initMap() {
        supportFragmentManager.beginTransaction()
            .replace(R.id.map_layout, SupportMapFragment.newInstance(this).apply {
                mTencentMap = map.apply {
                    isMyLocationEnabled = true
                    setLocationSource(this@MapActivity)
                    setMyLocationStyle(
                        MyLocationStyle()
                            .strokeColor(Color.TRANSPARENT)
                            .strokeWidth(0)
                            .fillColor(Color.TRANSPARENT)
                            .icon(BitmapDescriptorFactory.fromResource(R.drawable.biu))
                    )

                    setOnCameraChangeListener(object : TencentMap.OnCameraChangeListener {
                        override fun onCameraChange(cameraPosition: CameraPosition) {
                        }

                        override fun onCameraChangeFinished(cameraPosition: CameraPosition) {
                            Log.e(TAG, "onCameraChangeFinished: ${cameraPosition.target}")
                            if (isLocationOk) {
                                geo(cameraPosition.target)
                            }
                        }
                    })
                }
            })
            .commitAllowingStateLoss()

        mTencentMap.addOnMapLoadedCallback {
            Log.e(TAG, "地图加载完成")
        }
    }

    private fun initView() {

        binding.toolBar.setNavigationOnClickListener {
            finish()
        }

        binding.btnSubmit.setOnClickListener {
            if (mPoiAdapter.poiInfo == null) {
                Toast.makeText(this, "请选择地址", Toast.LENGTH_SHORT).show()
            } else {
                val latlng = mPoiAdapter.poiInfo!!.poi.latLng
                MainReceiver.sendLatLng(this, latlng.latitude, latlng.longitude)
                SpManager.putSP(
                    com.lishang.location.helper.config.Config.KEY_ADDRESS,
                    mPoiAdapter.poiInfo!!.poi.title
                )
                finish()
            }
        }


        binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(this@MapActivity)
            addItemDecoration(
                DividerItemDecoration(
                    this@MapActivity,
                    DividerItemDecoration.VERTICAL
                )
            )
            itemAnimator = null
            adapter = mPoiAdapter
        }
        mPoiAdapter.addLoadStateListener {
            Log.e(TAG, "addLoadStateListener: ${it.refresh} ${mPoiAdapter.itemCount} ")

            when (it.refresh) {
                is LoadState.NotLoading -> {
                    binding.loadingBar.isVisible = false
                    binding.txtStatus.isVisible = false
                    binding.recyclerView.isVisible = true
                    binding.btnSubmit.isEnabled = true
                }
                is LoadState.Loading -> {
                    binding.loadingBar.isVisible = true
                    binding.txtStatus.isVisible = false
                    binding.recyclerView.isVisible = false
                }
                is LoadState.Error -> {
                    binding.loadingBar.isVisible = false
                    binding.txtStatus.isVisible = true
                    binding.recyclerView.isVisible = false
                }
            }
        }
//        mPoiAdapter.withLoadStateHeader(mHeaderAdapter)
    }

    private fun addMarker(latLng: LatLng) {
        mClickMarker?.apply {
            remove()
        }
        mClickMarker = mTencentMap.addMarker(
            MarkerOptions(latLng).icon(centerPositionDrawable).fastLoad(false)
        )

    }

    override fun activate(listener: LocationSource.OnLocationChangedListener) {
        mLocationChangedListener = listener

        //开启定位
        val err: Int = mLocationManager.requestSingleFreshLocation(
            null, this, Looper.myLooper()
        )
        Log.e(TAG, "activate: $err")
    }

    override fun deactivate() {
        //当不需要展示定位点时，需要停止定位并释放相关资源
        mLocationManager.removeUpdates(this)
        mLocationChangedListener = null
    }

    override fun onLocationChanged(tencentLocation: TencentLocation, code: Int, msg: String?) {
        if (code == TencentLocation.ERROR_OK) {
            mLocationChangedListener?.apply {
                isLocationOk = true

                val location = Location(tencentLocation.provider)
                //设置经纬度
                //设置经纬度
                location.setLatitude(tencentLocation.latitude)
                location.setLongitude(tencentLocation.longitude)
                //设置精度，这个值会被设置为定位点上表示精度的圆形半径
                //设置精度，这个值会被设置为定位点上表示精度的圆形半径
                location.setAccuracy(tencentLocation.accuracy)
                //设置定位标的旋转角度，注意 tencentLocation.getBearing() 只有在 gps 时才有可能获取
                //设置定位标的旋转角度，注意 tencentLocation.getBearing() 只有在 gps 时才有可能获取
                location.setBearing(tencentLocation.bearing as Float)
                //将位置信息返回给地图
                //将位置信息返回给地图
                onLocationChanged(location)
                Log.e(TAG, "onLocationChanged: ")

            }
        }
    }


    override fun onStatusUpdate(p0: String?, p1: Int, p2: String?) {
    }

    fun onLocationClick(view: View) {
        //开启定位
        val err: Int = mLocationManager.requestSingleFreshLocation(
            null, this, Looper.myLooper()
        )
    }

    private fun geo(latLng: LatLng) {
        lifecycleScope.launchWhenResumed {
            Pager(
                config = PagingConfig(20),
                pagingSourceFactory = { PoiPagingSource(mSearchPoi, latLng) }
            ).flow.collect {
                mPoiAdapter.poiInfo = null
                mPoiAdapter.submitData(it)
            }
        }
    }

}

class PoiAdapter : PagingDataAdapter<PoiInfo, PoiViewHolder>(COMPARATOR) {
    companion object {
        private val COMPARATOR = object : DiffUtil.ItemCallback<PoiInfo>() {
            override fun areItemsTheSame(oldItem: PoiInfo, newItem: PoiInfo): Boolean {
                return oldItem.poi.id == newItem.poi.id
            }

            @SuppressLint("DiffUtilEquals")
            override fun areContentsTheSame(oldItem: PoiInfo, newItem: PoiInfo): Boolean {
                return oldItem.isSelect == newItem.isSelect
            }
        }
    }

    var poiInfo: PoiInfo? = null

    override fun onBindViewHolder(holder: PoiViewHolder, position: Int) {
        val item = getItem(position)
        if (poiInfo == null && position == 0) {
            poiInfo = item?.apply {
                isSelect = true
            }
        }
        holder.apply {
            bind.txtPoiName.text = item!!.poi.title
            bind.txtPoiAddress.text = item.poi.address
            bind.imgSelect.isInvisible = item.isSelect.not()
            bind.root.setOnClickListener {
                poiInfo?.isSelect = false
                item.isSelect = true
                poiInfo = item
                notifyDataSetChanged()
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PoiViewHolder =
        PoiViewHolder(
            ItemPoiLayoutBinding.bind(
                LayoutInflater.from(parent.context).inflate(R.layout.item_poi_layout, parent, false)
            )
        )
}

class PoiViewHolder(val bind: ItemPoiLayoutBinding) : RecyclerView.ViewHolder(bind.root)

class PoiSearch(context: Context) {
    private val mSearch: TencentSearch = TencentSearch(context)

    suspend fun geo(param: GeoParam) = suspendCoroutine<List<PoiInfo>> {
        Log.e("PoiSearch", "geo: param:${param.page}")
        mSearch.geo2address(Geo2AddressParam(param.latLng)
            .getPoi(true)
            .setPoiOptions(
                Geo2AddressParam.PoiOptions().setPageIndex(param.page).setPageSize(20)
                    .setRadius(100)
            ), object :
            HttpResponseListener<BaseObject> {
            override fun onSuccess(p0: Int, p1: BaseObject?) {
                Log.e("PoiSearch", "onSuccess: $p0")

                if (p1 == null) {
                    it.resume(emptyList())
                } else {
                    val obj = p1 as Geo2AddressResultObject

                    it.resume(obj.result.pois.map {
                        PoiInfo(it)
                    })
                }

            }

            override fun onFailure(p0: Int, p1: String?, p2: Throwable?) {
                Log.e("PoiSearch", "onFailure: $p1")
                it.resume(emptyList())
            }
        })
    }

}

class PoiPagingSource(private val search: PoiSearch, private val latLng: LatLng) :
    PagingSource<GeoParam, PoiInfo>() {
    override fun getRefreshKey(state: PagingState<GeoParam, PoiInfo>): GeoParam? =
        null

    override suspend fun load(params: LoadParams<GeoParam>): LoadResult<GeoParam, PoiInfo> {
        val param = params.key ?: GeoParam(1, LatLng(latLng))
        val result = search.geo(param)
        val prevKey = if (param.page > 1) GeoParam(param.page - 1, param.latLng) else null
        val nextKey = if (result.isNotEmpty()) GeoParam(param.page + 1, param.latLng) else null

        return LoadResult.Page(result, prevKey, nextKey)

    }

}

data class GeoParam(val page: Int, val latLng: LatLng)

data class PoiInfo(val poi: Poi, var isSelect: Boolean = false)
